library(beeswarm)
library(naniar)
library(zoo)

Attaching package: ‘zoo’

The following objects are masked from ‘package:base’:

    as.Date, as.Date.numeric
# install.packages("zoo")
library(janitor)

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
# install.packages("GGally")
# library(sets)
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
── Attaching packages ──────────────────────────────────────────────────────────────────────── tidyverse 1.3.0 ──
✓ ggplot2 3.3.3     ✓ purrr   0.3.4
✓ tibble  3.0.6     ✓ stringr 1.4.0
✓ tidyr   1.1.2     ✓ forcats 0.5.1
✓ readr   1.4.0     
── Conflicts ─────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(ggplot2)
library(GGally) # for ggpairs
Registered S3 method overwritten by 'GGally':
  method from   
  +.gg   ggplot2
library(lubridate)

Attaching package: ‘lubridate’

The following objects are masked from ‘package:base’:

    date, intersect, setdiff, union
# install.packages("maps")
# library(maps)
load_file <- function(file_path){
  read_csv(file_path)
}

tx_data <- load_file("./../data/COVID-19_cases_TX.csv")

── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
cols(
  county_fips_code = col_character(),
  county_name = col_character(),
  state = col_character(),
  state_fips_code = col_double(),
  date = col_date(format = ""),
  confirmed_cases = col_double(),
  deaths = col_double()
)
global_mobility_report <- load_file("./../data/Global_Mobility_Report.csv")

── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
cols(
  country_region_code = col_character(),
  country_region = col_character(),
  sub_region_1 = col_character(),
  sub_region_2 = col_logical(),
  metro_area = col_logical(),
  iso_3166_2_code = col_character(),
  census_fips_code = col_logical(),
  date = col_date(format = ""),
  retail_and_recreation_percent_change_from_baseline = col_double(),
  grocery_and_pharmacy_percent_change_from_baseline = col_double(),
  parks_percent_change_from_baseline = col_double(),
  transit_stations_percent_change_from_baseline = col_double(),
  workplaces_percent_change_from_baseline = col_double(),
  residential_percent_change_from_baseline = col_double()
)

4199216 parsing failures.
 row        col           expected                  actual                                   file
3036 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3037 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3038 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3039 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
3040 metro_area 1/0/T/F/TRUE/FALSE Kabul Metropolitan Area './../data/Global_Mobility_Report.csv'
.... .......... .................. ....................... ......................................
See problems(...) for more details.
cases_plus_census <- load_file("./../data/COVID-19_cases_plus_census.csv")

── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
cols(
  .default = col_double(),
  county_fips_code = col_character(),
  county_name = col_character(),
  state = col_character(),
  state_fips_code = col_character(),
  date = col_date(format = ""),
  geo_id = col_character(),
  pop_5_years_over = col_logical(),
  speak_only_english_at_home = col_logical(),
  speak_spanish_at_home = col_logical(),
  speak_spanish_at_home_low_english = col_logical(),
  pop_15_and_over = col_logical(),
  pop_never_married = col_logical(),
  pop_now_married = col_logical(),
  pop_separated = col_logical(),
  pop_widowed = col_logical(),
  pop_divorced = col_logical()
)
ℹ Use `spec()` for the full column specifications.
cols_keep <- c("county_fips_code", "confirmed_cases", "deaths", "median_income", "male_pop", "female_pop", "total_pop", "median_age", "worked_at_home")
subset_census <- cases_plus_census[cols_keep]

# cols_keep <- c("date", "retail_and_recreation_percent_change_from_baseline", "grocery_and_pharmacy_percent_change_from_baseline", "parks_percent_change_from_baseline", "transit_stations_percent_change_from_baseline", "workplaces_percent_change_from_baseline", "residential_percent_change_from_baseline")
# subset_mobility <- global_mobility_report[cols_keep]
# glo
# subset_mobility$date <- as.Date(subset_mobility$date, format="%Y-%m-%d")
# global_mobility_report
vis_miss(global_mobility_report, sort_miss = T, warn_large_data= F)

vis_miss(tx_data, sort_miss = T, warn_large_data= F)

vis_miss(subset_census, sort_miss = T, warn_large_data = F)

library(RColorBrewer)
plot_vs_county <- function(df, col_val, percentile=FALSE,
                           fips_title="county_fips_code", banks=6, 
                           legend_title="", graphic_title=""){
  # Subset for speed 
  df <- df[c(fips_title, col_val)]
  
  # Get county data
  gcounty <- ggplot2::map_data("county")
  # USA map data
  gusa <- map_data("state")
  
  if (banks > 9){
    mycolors <- colorRampPalette(brewer.pal(9, "Reds"))(banks)
  }
  
  # Format with subregions
  fipstab <-
      transmute(maps::county.fips, fips, county = sub(":.*", "", polyname)) %>%
      unique() %>%
      separate(county, c("region", "subregion"), sep = ",")
  
  # Combine in desired order (NA for missing)
  gcounty <- left_join(gcounty, fipstab, c("region", "subregion"))


  dis <- df
  dis$rprop <- rank(df[col_val])
  dis$pcls <- cut(100 * percent_rank(df[col_val]), seq(0, 100, len = banks),
                        include.lowest = TRUE)

  # Missing data
  anti_join(gcounty, dis, by = c("fips" = fips_title)) %>%
    select(region, subregion) %>%
    unique()
  gcounty_pop <- left_join(gcounty, dis, by = c("fips" = fips_title))
  fill_vals <- gcounty_pop[col_val]

  # Plot
  if (legend_title == ""){
    legend_title <- col_val
  }

  if (percentile == FALSE){
    # names(gcounty_pop)[names(gcounty_pop) == col_val] <- "col_of_interest"
    plt <- ggplot(gcounty_pop) +
      geom_polygon(aes(long, lat, group = group, fill = get(col_val)),
                   color = "grey", size = 0.1, name="Percent Infected") +
      geom_polygon(aes(long, lat, group = group),
                   fill = NA, data = gusa, color = "lightgrey") +
      coord_map("bonne", parameters = 41.6) + ggthemes::theme_map()+
      scale_fill_gradient2()
       # scale_fill_gradient(low = "white", high = "red", na.value = "grey")
      # scale_fill_gradientn(colours = terrain.colors(10))
  }

  if (percentile == TRUE){
    plt <- ggplot(gcounty_pop) +
      geom_polygon(aes(long, lat, group = group, fill = pcls),
                   color = "grey", size = 0.1) +
      geom_polygon(aes(long, lat, group = group),
                   fill = NA, data = gusa, color = "lightgrey") +
      coord_map("bonne", parameters = 41.6) + ggthemes::theme_map() +
      scale_fill_manual(values = mycolors, na.value = "grey") +
      # scale_fill_brewer(palette = "viridis", na.value = "grey") +
      theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
            legend.background = element_rect(fill = NA), 
            legend.position = "left")
  }
  plt <- plt + labs(fill=legend_title) + ggtitle(graphic_title)
  plt
}
subset_census
subset_census['pct_infected'] <- subset_census['confirmed_cases']/subset_census['total_pop']
subset_census['pct_deaths'] <- subset_census['deaths']/subset_census['total_pop']
subset_census$county_fips_code <-as.integer(subset_census$county_fips_code)
subset_census
plot_vs_county(subset_census, "pct_infected", legend_title = "Percent Infected")
Ignoring unknown parameters: name

plot_vs_county(subset_census, "pct_infected", percentile = TRUE, banks=11, 
               legend_title = "Percentile Infected",
               graphic_title = "Percentile of Percentage of People Infected by County")

plot_vs_county(subset_census, "pct_deaths", percentile = TRUE, banks=11, 
               legend_title = "Percentile Deaths",
               graphic_title = "Percentile of Percentage of Deaths by County")

census_corr_cols <- c("deaths", "confirmed_cases", "median_income", "male_pop",
                      "female_pop", "total_pop", "median_age", "worked_at_home")
ggcorr(subset_census[census_corr_cols], low="red", mid="grey", high="blue", hjust= .75, size=3, 
       label = TRUE, label_size = 3, label_color = "white") + ggplot2::labs(title = "Pearson Correlation of Important Variables")

global_mobility_report
country_date_pct_change <- global_mobility_report %>% select(country_region_code
                                                             | contains("date") 
                                                             | contains("percent"))
country_date_pct_change
coi_downsampled <- country_date_pct_change %>% filter(country_region_code %in% 
                                                        c("US", "CA", "NZ", "AE", "CN", "DE", "JP")) %>% 
  filter(weekdays(date) == "Monday") %>% group_by(country_region_code, date) %>% summarise_all(mean, na.rm = T) %>% arrange(country_region_code, date)
coi_downsampled
interested_cols <- c("retail_and_recreation_percent_change_from_baseline",
                     "grocery_and_pharmacy_percent_change_from_baseline",
                     "parks_percent_change_from_baseline",
                     "transit_stations_percent_change_from_baseline",
                     "workplaces_percent_change_from_baseline",
                     "residential_percent_change_from_baseline")

col_labels <- c("Average Retail and Recreation Percent Change from Baseline",
                     "Average Grocery and Pharmacy Percent Change from Baseline",
                     "Average Parks Percent Change from Baseline",
                     "Average Transit Stations Percent Change from Baseline",
                     "Average Workplaces Percent Change from Baseline",
                     "Average Residential Percent Change from Baseline")


for (i in 1:length(col_labels)){
  print(i)
  plt <- ggplot(coi_downsampled,
       aes(x=date, y=get(interested_cols[i]), group=country_region_code,
                            color=country_region_code))+
  geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
  geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
  # geom_point(size=.5)+geom_line()+
  labs(y = col_labels[i], x = "Date", color = "Country")+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
        axis.title.y = element_text(size = 8))
  save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
  ggsave(save_path)
  print(plt)
}
[1] 1
Saving 7 x 7 in image
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6

# ggplot(coi_downsampled,
#        aes(x=date, y=grocery_and_pharmacy_percent_change_from_baseline, group=country_region_code,
#                             color=country_region_code))+
#   geom_point(aes(y=rollmean(retail_and_recreation_percent_change_from_baseline, k=10, na.pad=TRUE)), size=.5)+
#   geom_line(aes(y=rollmean(retail_and_recreation_percent_change_from_baseline, k=10, na.pad=TRUE)))+
#   # geom_point(size=.5)+geom_line()+
#   labs(y = "Average Grocery and Pharmacy Percent Change from Baseline", x = "Date", color = "Country")+
#   theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#         axis.title.y = element_text(size = 8))
#   # geom_line()
tx_county_data <- tx_data %>% filter(county_name != "Statewide Unallocated")
tx_total_state_data <- tx_data %>% filter(county_name == "Statewide Unallocated")
tx_total_state_data$cumulative_deaths <- cumsum(tx_total_state_data$deaths)
tx_total_state_data$cumulative_cases <- cumsum(tx_total_state_data$confirmed_cases)
tx_county_data
tx_total_state_data
interested_cols <- c("confirmed_cases", "deaths", "cumulative_deaths", "cumulative_cases")
col_labels <- c("Confirmed Cases Per Day", "Deaths Per Day", "Total Deaths", "Total Cases")

for (i in 1:length(col_labels)){
  print(i)
  plt <- ggplot(tx_total_state_data,
       aes(x=date, y=get(interested_cols[i])))+
  # geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
  # geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
  # geom_point(size=.5)+geom_line()+
    geom_line()+
  labs(y = col_labels[i], x = "Date")
  # theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
  #       axis.title.y = element_text(size = 8))
  # save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
  # ggsave(save_path)
  print(plt)
}
[1] 1
[1] 2
[1] 3
[1] 4

Since the above doesn’t really make sense (only 78 confirmed cases with over a thousand deaths), I am going to analyze on a per county basis and maybe that data will be more clear.

tx_by_day_based_on_county <- tx_county_data %>% 
  select(date, confirmed_cases, deaths) %>%
  group_by(date) %>% 
  summarise_all(sum, na.rm = T) %>%
  arrange(date)

interested_cols <- c("confirmed_cases", "deaths")
col_labels <- c("Total Cases", "Total Deaths")

for (i in 1:length(col_labels)){
  print(i)
  plt <- ggplot(tx_by_day_based_on_county,
       aes(x=date, y=get(interested_cols[i])))+
  # geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
  # geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
  geom_point(size=.5)+geom_line()+
    # geom_line()+
  labs(y = col_labels[i], x = "Date")
  # theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
  #       axis.title.y = element_text(size = 8))
  # save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
  # ggsave(save_path)
  print(plt)
}
[1] 1
[1] 2

tx_by_day_based_on_county
library(scales)
# tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count")
ggplot(tx_by_day_based_on_county %>% pivot_longer(!date, names_to = "type", values_to = "count"),
       aes(x=date, y=count, group=type, color = type))+
         geom_line()+
  scale_y_continuous(trans = "log10",
                     labels = trans_breaks('log10', math_format(10^.x)))+
  scale_color_manual(labels = c("Confirmed Cases", "Deaths"), values = c("confirmed_cases"="blue",
                                                                         "deaths"="red"))+
  labs(y = "Total Persons", x = "Date", color = "")+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)))+
  ggtitle("Texas COVID-19 Cases")
  ggsave("./../imgs/texas_covid_cases_total.png")
Saving 7.29 x 4.51 in image

  # scale_y_log10()
         # labs(y = "Total Persons", x = "Date"))

# )
# 
# plt <- ggplot(coi_downsampled,
#        aes(x=date, y=get(interested_cols[i]), group=country_region_code,
#                             color=country_region_code))+
#   geom_point(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)), size=.5)+
#   geom_line(aes(y=rollmean(get(interested_cols[i]), k=10, na.pad=TRUE)))+
#   # geom_point(size=.5)+geom_line()+
#   labs(y = col_labels[i], x = "Date", color = "Country")+
#   theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)),
#         axis.title.y = element_text(size = 8))
#   save_path <- paste(c("./../imgs/", interested_cols[i], ".png"), collapse = "")
#   ggsave(save_path)
#   print(plt)
tx_county_data
tx_state <- map_data("state") %>% subset(region == "texas")
tx_county_map_data <- map_data("county") %>% subset(region == "texas")

tx_state
tx_county_map_data

# Lowercase
tx_county_data$county_name <- tolower(tx_county_data$county_name)

# Remove ' county'
tx_county_data$county_name <- sub("\\s*county\\b.*", "", tx_county_data$county_name)
tx_county_data

# Join the data with state geo info
tx_geo_data <- left_join(tx_county_map_data, tx_county_data, by = c("subregion" = "county_name"))
tx_geo_data
tx_geo_data$county_fips_code <- as.integer(tx_geo_data$county_fips_code)
plot_vs_county(tx_geo_data, "confirmed_cases")
Ignoring unknown parameters: name

# dallas_data <- tx_county_data %>% filter(county_name == "dallas") 
dallas_data <- tx_county_data %>% filter(county_name == "dallas") %>% 
  select(date, confirmed_cases, deaths)

ggplot(dallas_data %>% pivot_longer(!date, names_to = "type", values_to = "count"),
       aes(x=date, y=count, group=type, color = type))+
         geom_line()+
  scale_y_continuous(trans = "log10", labels = trans_breaks("log10", math_format(10^.x)))+
  scale_y_log10(breaks=c(100, 300, 500, 1000, 3000, 5000, 10000, 30000, 50000, 100000, 300000),
                labels=c('100', '300', '500', '1000', '3000', '5000', '10000', '30000', '50000', '100000', '300000'))+
  scale_color_manual(labels = c("Confirmed Cases", "Deaths"), values = c("confirmed_cases"="blue",
                                                                         "deaths"="red"))+
  labs(y = "Total Persons", x = "Date", color = "")+
  theme(plot.title = element_text(family = "Helvetica", face = "bold", size = (15)))+
  ggtitle("Dallas COVID-19 Cases")
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.
  ggsave("./../imgs/dallas_covid_cases_total.png")
Saving 7.29 x 4.51 in image

subset_census
LS0tCnRpdGxlOiAiQ2xlYW5lZCBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKYGBge3J9CmxpYnJhcnkoYmVlc3dhcm0pCmxpYnJhcnkobmFuaWFyKQpsaWJyYXJ5KHpvbykKIyBpbnN0YWxsLnBhY2thZ2VzKCJ6b28iKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoZHBseXIpCiMgaW5zdGFsbC5wYWNrYWdlcygiR0dhbGx5IikKIyBsaWJyYXJ5KHNldHMpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoR0dhbGx5KSAjIGZvciBnZ3BhaXJzCmxpYnJhcnkobHVicmlkYXRlKQojIGluc3RhbGwucGFja2FnZXMoIm1hcHMiKQojIGxpYnJhcnkobWFwcykKYGBgCgpgYGB7cn0KbG9hZF9maWxlIDwtIGZ1bmN0aW9uKGZpbGVfcGF0aCl7CiAgcmVhZF9jc3YoZmlsZV9wYXRoKQp9Cgp0eF9kYXRhIDwtIGxvYWRfZmlsZSgiLi8uLi9kYXRhL0NPVklELTE5X2Nhc2VzX1RYLmNzdiIpCmdsb2JhbF9tb2JpbGl0eV9yZXBvcnQgPC0gbG9hZF9maWxlKCIuLy4uL2RhdGEvR2xvYmFsX01vYmlsaXR5X1JlcG9ydC5jc3YiKQpjYXNlc19wbHVzX2NlbnN1cyA8LSBsb2FkX2ZpbGUoIi4vLi4vZGF0YS9DT1ZJRC0xOV9jYXNlc19wbHVzX2NlbnN1cy5jc3YiKQpgYGAKYGBge3J9CmNvbHNfa2VlcCA8LSBjKCJjb3VudHlfZmlwc19jb2RlIiwgImNvbmZpcm1lZF9jYXNlcyIsICJkZWF0aHMiLCAibWVkaWFuX2luY29tZSIsICJtYWxlX3BvcCIsICJmZW1hbGVfcG9wIiwgInRvdGFsX3BvcCIsICJtZWRpYW5fYWdlIiwgIndvcmtlZF9hdF9ob21lIikKc3Vic2V0X2NlbnN1cyA8LSBjYXNlc19wbHVzX2NlbnN1c1tjb2xzX2tlZXBdCgojIGNvbHNfa2VlcCA8LSBjKCJkYXRlIiwgInJldGFpbF9hbmRfcmVjcmVhdGlvbl9wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwgImdyb2NlcnlfYW5kX3BoYXJtYWN5X3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLCAicGFya3NfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSIsICJ0cmFuc2l0X3N0YXRpb25zX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLCAid29ya3BsYWNlc19wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwgInJlc2lkZW50aWFsX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiKQojIHN1YnNldF9tb2JpbGl0eSA8LSBnbG9iYWxfbW9iaWxpdHlfcmVwb3J0W2NvbHNfa2VlcF0KIyBnbG8KIyBzdWJzZXRfbW9iaWxpdHkkZGF0ZSA8LSBhcy5EYXRlKHN1YnNldF9tb2JpbGl0eSRkYXRlLCBmb3JtYXQ9IiVZLSVtLSVkIikKYGBgCgpgYGB7cn0KIyBnbG9iYWxfbW9iaWxpdHlfcmVwb3J0CnZpc19taXNzKGdsb2JhbF9tb2JpbGl0eV9yZXBvcnQsIHNvcnRfbWlzcyA9IFQsIHdhcm5fbGFyZ2VfZGF0YT0gRikKYGBgCgoKYGBge3J9CnZpc19taXNzKHR4X2RhdGEsIHNvcnRfbWlzcyA9IFQsIHdhcm5fbGFyZ2VfZGF0YT0gRikKdmlzX21pc3Moc3Vic2V0X2NlbnN1cywgc29ydF9taXNzID0gVCwgd2Fybl9sYXJnZV9kYXRhID0gRikKYGBgCgpgYGB7cn0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCnBsb3RfdnNfY291bnR5IDwtIGZ1bmN0aW9uKGRmLCBjb2xfdmFsLCBwZXJjZW50aWxlPUZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICAgICBmaXBzX3RpdGxlPSJjb3VudHlfZmlwc19jb2RlIiwgYmFua3M9NiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZF90aXRsZT0iIiwgZ3JhcGhpY190aXRsZT0iIil7CiAgIyBTdWJzZXQgZm9yIHNwZWVkIAogIGRmIDwtIGRmW2MoZmlwc190aXRsZSwgY29sX3ZhbCldCiAgCiAgIyBHZXQgY291bnR5IGRhdGEKICBnY291bnR5IDwtIGdncGxvdDI6Om1hcF9kYXRhKCJjb3VudHkiKQogICMgVVNBIG1hcCBkYXRhCiAgZ3VzYSA8LSBtYXBfZGF0YSgic3RhdGUiKQogIAogIGlmIChiYW5rcyA+IDkpewogICAgbXljb2xvcnMgPC0gY29sb3JSYW1wUGFsZXR0ZShicmV3ZXIucGFsKDksICJSZWRzIikpKGJhbmtzKQogIH0KICAKICAjIEZvcm1hdCB3aXRoIHN1YnJlZ2lvbnMKICBmaXBzdGFiIDwtCiAgICAgIHRyYW5zbXV0ZShtYXBzOjpjb3VudHkuZmlwcywgZmlwcywgY291bnR5ID0gc3ViKCI6LioiLCAiIiwgcG9seW5hbWUpKSAlPiUKICAgICAgdW5pcXVlKCkgJT4lCiAgICAgIHNlcGFyYXRlKGNvdW50eSwgYygicmVnaW9uIiwgInN1YnJlZ2lvbiIpLCBzZXAgPSAiLCIpCiAgCiAgIyBDb21iaW5lIGluIGRlc2lyZWQgb3JkZXIgKE5BIGZvciBtaXNzaW5nKQogIGdjb3VudHkgPC0gbGVmdF9qb2luKGdjb3VudHksIGZpcHN0YWIsIGMoInJlZ2lvbiIsICJzdWJyZWdpb24iKSkKCgogIGRpcyA8LSBkZgogIGRpcyRycHJvcCA8LSByYW5rKGRmW2NvbF92YWxdKQogIGRpcyRwY2xzIDwtIGN1dCgxMDAgKiBwZXJjZW50X3JhbmsoZGZbY29sX3ZhbF0pLCBzZXEoMCwgMTAwLCBsZW4gPSBiYW5rcyksCiAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkKCiAgIyBNaXNzaW5nIGRhdGEKICBhbnRpX2pvaW4oZ2NvdW50eSwgZGlzLCBieSA9IGMoImZpcHMiID0gZmlwc190aXRsZSkpICU+JQogICAgc2VsZWN0KHJlZ2lvbiwgc3VicmVnaW9uKSAlPiUKICAgIHVuaXF1ZSgpCiAgZ2NvdW50eV9wb3AgPC0gbGVmdF9qb2luKGdjb3VudHksIGRpcywgYnkgPSBjKCJmaXBzIiA9IGZpcHNfdGl0bGUpKQogIGZpbGxfdmFscyA8LSBnY291bnR5X3BvcFtjb2xfdmFsXQoKICAjIFBsb3QKICBpZiAobGVnZW5kX3RpdGxlID09ICIiKXsKICAgIGxlZ2VuZF90aXRsZSA8LSBjb2xfdmFsCiAgfQoKICBpZiAocGVyY2VudGlsZSA9PSBGQUxTRSl7CiAgICAjIG5hbWVzKGdjb3VudHlfcG9wKVtuYW1lcyhnY291bnR5X3BvcCkgPT0gY29sX3ZhbF0gPC0gImNvbF9vZl9pbnRlcmVzdCIKICAgIHBsdCA8LSBnZ3Bsb3QoZ2NvdW50eV9wb3ApICsKICAgICAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBnZXQoY29sX3ZhbCkpLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjEsIG5hbWU9IlBlcmNlbnQgSW5mZWN0ZWQiKSArCiAgICAgIGdlb21fcG9seWdvbihhZXMobG9uZywgbGF0LCBncm91cCA9IGdyb3VwKSwKICAgICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwgZGF0YSA9IGd1c2EsIGNvbG9yID0gImxpZ2h0Z3JleSIpICsKICAgICAgY29vcmRfbWFwKCJib25uZSIsIHBhcmFtZXRlcnMgPSA0MS42KSArIGdndGhlbWVzOjp0aGVtZV9tYXAoKSsKICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudDIoKQogICAgICAgIyBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIiwgbmEudmFsdWUgPSAiZ3JleSIpCiAgICAgICMgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3VycyA9IHRlcnJhaW4uY29sb3JzKDEwKSkKICB9CgogIGlmIChwZXJjZW50aWxlID09IFRSVUUpewogICAgcGx0IDwtIGdncGxvdChnY291bnR5X3BvcCkgKwogICAgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHBjbHMpLAogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjEpICsKICAgICAgZ2VvbV9wb2x5Z29uKGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApLAogICAgICAgICAgICAgICAgICAgZmlsbCA9IE5BLCBkYXRhID0gZ3VzYSwgY29sb3IgPSAibGlnaHRncmV5IikgKwogICAgICBjb29yZF9tYXAoImJvbm5lIiwgcGFyYW1ldGVycyA9IDQxLjYpICsgZ2d0aGVtZXM6OnRoZW1lX21hcCgpICsKICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gbXljb2xvcnMsIG5hLnZhbHVlID0gImdyZXkiKSArCiAgICAgICMgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJ2aXJpZGlzIiwgbmEudmFsdWUgPSAiZ3JleSIpICsKICAgICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpLAogICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gTkEpLCAKICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImxlZnQiKQogIH0KICBwbHQgPC0gcGx0ICsgbGFicyhmaWxsPWxlZ2VuZF90aXRsZSkgKyBnZ3RpdGxlKGdyYXBoaWNfdGl0bGUpCiAgcGx0Cn0KYGBgCgpgYGB7cn0Kc3Vic2V0X2NlbnN1cwpgYGAKCmBgYHtyfQpzdWJzZXRfY2Vuc3VzWydwY3RfaW5mZWN0ZWQnXSA8LSBzdWJzZXRfY2Vuc3VzWydjb25maXJtZWRfY2FzZXMnXS9zdWJzZXRfY2Vuc3VzWyd0b3RhbF9wb3AnXQpzdWJzZXRfY2Vuc3VzWydwY3RfZGVhdGhzJ10gPC0gc3Vic2V0X2NlbnN1c1snZGVhdGhzJ10vc3Vic2V0X2NlbnN1c1sndG90YWxfcG9wJ10Kc3Vic2V0X2NlbnN1cyRjb3VudHlfZmlwc19jb2RlIDwtYXMuaW50ZWdlcihzdWJzZXRfY2Vuc3VzJGNvdW50eV9maXBzX2NvZGUpCnN1YnNldF9jZW5zdXMKYGBgCmBgYHtyfQpwbG90X3ZzX2NvdW50eShzdWJzZXRfY2Vuc3VzLCAicGN0X2luZmVjdGVkIiwgbGVnZW5kX3RpdGxlID0gIlBlcmNlbnQgSW5mZWN0ZWQiKQpwbG90X3ZzX2NvdW50eShzdWJzZXRfY2Vuc3VzLCAicGN0X2luZmVjdGVkIiwgcGVyY2VudGlsZSA9IFRSVUUsIGJhbmtzPTExLCAKICAgICAgICAgICAgICAgbGVnZW5kX3RpdGxlID0gIlBlcmNlbnRpbGUgSW5mZWN0ZWQiLAogICAgICAgICAgICAgICBncmFwaGljX3RpdGxlID0gIlBlcmNlbnRpbGUgb2YgUGVyY2VudGFnZSBvZiBQZW9wbGUgSW5mZWN0ZWQgYnkgQ291bnR5IikKcGxvdF92c19jb3VudHkoc3Vic2V0X2NlbnN1cywgInBjdF9kZWF0aHMiLCBwZXJjZW50aWxlID0gVFJVRSwgYmFua3M9MTEsIAogICAgICAgICAgICAgICBsZWdlbmRfdGl0bGUgPSAiUGVyY2VudGlsZSBEZWF0aHMiLAogICAgICAgICAgICAgICBncmFwaGljX3RpdGxlID0gIlBlcmNlbnRpbGUgb2YgUGVyY2VudGFnZSBvZiBEZWF0aHMgYnkgQ291bnR5IikKYGBgCgpgYGB7cn0KY2Vuc3VzX2NvcnJfY29scyA8LSBjKCJkZWF0aHMiLCAiY29uZmlybWVkX2Nhc2VzIiwgIm1lZGlhbl9pbmNvbWUiLCAibWFsZV9wb3AiLAogICAgICAgICAgICAgICAgICAgICAgImZlbWFsZV9wb3AiLCAidG90YWxfcG9wIiwgIm1lZGlhbl9hZ2UiLCAid29ya2VkX2F0X2hvbWUiKQpnZ2NvcnIoc3Vic2V0X2NlbnN1c1tjZW5zdXNfY29ycl9jb2xzXSwgbG93PSJyZWQiLCBtaWQ9ImdyZXkiLCBoaWdoPSJibHVlIiwgaGp1c3Q9IC43NSwgc2l6ZT0zLCAKICAgICAgIGxhYmVsID0gVFJVRSwgbGFiZWxfc2l6ZSA9IDMsIGxhYmVsX2NvbG9yID0gIndoaXRlIikgKyBnZ3Bsb3QyOjpsYWJzKHRpdGxlID0gIlBlYXJzb24gQ29ycmVsYXRpb24gb2YgSW1wb3J0YW50IFZhcmlhYmxlcyIpCmBgYApgYGB7cn0KZ2xvYmFsX21vYmlsaXR5X3JlcG9ydApgYGAKCgpgYGB7cn0KY291bnRyeV9kYXRlX3BjdF9jaGFuZ2UgPC0gZ2xvYmFsX21vYmlsaXR5X3JlcG9ydCAlPiUgc2VsZWN0KGNvdW50cnlfcmVnaW9uX2NvZGUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgY29udGFpbnMoImRhdGUiKSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgY29udGFpbnMoInBlcmNlbnQiKSkKY291bnRyeV9kYXRlX3BjdF9jaGFuZ2UKYGBgCmBgYHtyfQpjb2lfZG93bnNhbXBsZWQgPC0gY291bnRyeV9kYXRlX3BjdF9jaGFuZ2UgJT4lIGZpbHRlcihjb3VudHJ5X3JlZ2lvbl9jb2RlICVpbiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiVVMiLCAiQ0EiLCAiTloiLCAiQUUiLCAiQ04iLCAiREUiLCAiSlAiKSkgJT4lIAogIGZpbHRlcih3ZWVrZGF5cyhkYXRlKSA9PSAiTW9uZGF5IikgJT4lIGdyb3VwX2J5KGNvdW50cnlfcmVnaW9uX2NvZGUsIGRhdGUpICU+JSBzdW1tYXJpc2VfYWxsKG1lYW4sIG5hLnJtID0gVCkgJT4lIGFycmFuZ2UoY291bnRyeV9yZWdpb25fY29kZSwgZGF0ZSkKY29pX2Rvd25zYW1wbGVkCmBgYAoKCgpgYGB7cn0KaW50ZXJlc3RlZF9jb2xzIDwtIGMoInJldGFpbF9hbmRfcmVjcmVhdGlvbl9wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwKICAgICAgICAgICAgICAgICAgICAgImdyb2NlcnlfYW5kX3BoYXJtYWN5X3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAicGFya3NfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJ0cmFuc2l0X3N0YXRpb25zX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAid29ya3BsYWNlc19wZXJjZW50X2NoYW5nZV9mcm9tX2Jhc2VsaW5lIiwKICAgICAgICAgICAgICAgICAgICAgInJlc2lkZW50aWFsX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUiKQoKY29sX2xhYmVscyA8LSBjKCJBdmVyYWdlIFJldGFpbCBhbmQgUmVjcmVhdGlvbiBQZXJjZW50IENoYW5nZSBmcm9tIEJhc2VsaW5lIiwKICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgR3JvY2VyeSBhbmQgUGhhcm1hY3kgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsCiAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIFBhcmtzIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBUcmFuc2l0IFN0YXRpb25zIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBXb3JrcGxhY2VzIFBlcmNlbnQgQ2hhbmdlIGZyb20gQmFzZWxpbmUiLAogICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBSZXNpZGVudGlhbCBQZXJjZW50IENoYW5nZSBmcm9tIEJhc2VsaW5lIikKCgpmb3IgKGkgaW4gMTpsZW5ndGgoY29sX2xhYmVscykpewogIHByaW50KGkpCiAgcGx0IDwtIGdncGxvdChjb2lfZG93bnNhbXBsZWQsCiAgICAgICBhZXMoeD1kYXRlLCB5PWdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBncm91cD1jb3VudHJ5X3JlZ2lvbl9jb2RlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9Y291bnRyeV9yZWdpb25fY29kZSkpKwogIGdlb21fcG9pbnQoYWVzKHk9cm9sbG1lYW4oZ2V0KGludGVyZXN0ZWRfY29sc1tpXSksIGs9MTAsIG5hLnBhZD1UUlVFKSksIHNpemU9LjUpKwogIGdlb21fbGluZShhZXMoeT1yb2xsbWVhbihnZXQoaW50ZXJlc3RlZF9jb2xzW2ldKSwgaz0xMCwgbmEucGFkPVRSVUUpKSkrCiAgIyBnZW9tX3BvaW50KHNpemU9LjUpK2dlb21fbGluZSgpKwogIGxhYnMoeSA9IGNvbF9sYWJlbHNbaV0sIHggPSAiRGF0ZSIsIGNvbG9yID0gIkNvdW50cnkiKSsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKICBzYXZlX3BhdGggPC0gcGFzdGUoYygiLi8uLi9pbWdzLyIsIGludGVyZXN0ZWRfY29sc1tpXSwgIi5wbmciKSwgY29sbGFwc2UgPSAiIikKICBnZ3NhdmUoc2F2ZV9wYXRoKQogIHByaW50KHBsdCkKfQojIGdncGxvdChjb2lfZG93bnNhbXBsZWQsCiMgICAgICAgIGFlcyh4PWRhdGUsIHk9Z3JvY2VyeV9hbmRfcGhhcm1hY3lfcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSwgZ3JvdXA9Y291bnRyeV9yZWdpb25fY29kZSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9Y291bnRyeV9yZWdpb25fY29kZSkpKwojICAgZ2VvbV9wb2ludChhZXMoeT1yb2xsbWVhbihyZXRhaWxfYW5kX3JlY3JlYXRpb25fcGVyY2VudF9jaGFuZ2VfZnJvbV9iYXNlbGluZSwgaz0xMCwgbmEucGFkPVRSVUUpKSwgc2l6ZT0uNSkrCiMgICBnZW9tX2xpbmUoYWVzKHk9cm9sbG1lYW4ocmV0YWlsX2FuZF9yZWNyZWF0aW9uX3BlcmNlbnRfY2hhbmdlX2Zyb21fYmFzZWxpbmUsIGs9MTAsIG5hLnBhZD1UUlVFKSkpKwojICAgIyBnZW9tX3BvaW50KHNpemU9LjUpK2dlb21fbGluZSgpKwojICAgbGFicyh5ID0gIkF2ZXJhZ2UgR3JvY2VyeSBhbmQgUGhhcm1hY3kgUGVyY2VudCBDaGFuZ2UgZnJvbSBCYXNlbGluZSIsIHggPSAiRGF0ZSIsIGNvbG9yID0gIkNvdW50cnkiKSsKIyAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwKIyAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCkpCiMgICAjIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CnR4X2NvdW50eV9kYXRhIDwtIHR4X2RhdGEgJT4lIGZpbHRlcihjb3VudHlfbmFtZSAhPSAiU3RhdGV3aWRlIFVuYWxsb2NhdGVkIikKdHhfdG90YWxfc3RhdGVfZGF0YSA8LSB0eF9kYXRhICU+JSBmaWx0ZXIoY291bnR5X25hbWUgPT0gIlN0YXRld2lkZSBVbmFsbG9jYXRlZCIpCnR4X3RvdGFsX3N0YXRlX2RhdGEkY3VtdWxhdGl2ZV9kZWF0aHMgPC0gY3Vtc3VtKHR4X3RvdGFsX3N0YXRlX2RhdGEkZGVhdGhzKQp0eF90b3RhbF9zdGF0ZV9kYXRhJGN1bXVsYXRpdmVfY2FzZXMgPC0gY3Vtc3VtKHR4X3RvdGFsX3N0YXRlX2RhdGEkY29uZmlybWVkX2Nhc2VzKQp0eF9jb3VudHlfZGF0YQp0eF90b3RhbF9zdGF0ZV9kYXRhCmBgYAoKYGBge3J9CgpgYGAKCmBgYHtyfQppbnRlcmVzdGVkX2NvbHMgPC0gYygiY29uZmlybWVkX2Nhc2VzIiwgImRlYXRocyIsICJjdW11bGF0aXZlX2RlYXRocyIsICJjdW11bGF0aXZlX2Nhc2VzIikKY29sX2xhYmVscyA8LSBjKCJDb25maXJtZWQgQ2FzZXMgUGVyIERheSIsICJEZWF0aHMgUGVyIERheSIsICJUb3RhbCBEZWF0aHMiLCAiVG90YWwgQ2FzZXMiKQoKZm9yIChpIGluIDE6bGVuZ3RoKGNvbF9sYWJlbHMpKXsKICBwcmludChpKQogIHBsdCA8LSBnZ3Bsb3QodHhfdG90YWxfc3RhdGVfZGF0YSwKICAgICAgIGFlcyh4PWRhdGUsIHk9Z2V0KGludGVyZXN0ZWRfY29sc1tpXSkpKSsKICAjIGdlb21fcG9pbnQoYWVzKHk9cm9sbG1lYW4oZ2V0KGludGVyZXN0ZWRfY29sc1tpXSksIGs9MTAsIG5hLnBhZD1UUlVFKSksIHNpemU9LjUpKwogICMgZ2VvbV9saW5lKGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpKSsKICAjIGdlb21fcG9pbnQoc2l6ZT0uNSkrZ2VvbV9saW5lKCkrCiAgICBnZW9tX2xpbmUoKSsKICBsYWJzKHkgPSBjb2xfbGFiZWxzW2ldLCB4ID0gIkRhdGUiKQogICMgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAiSGVsdmV0aWNhIiwgZmFjZSA9ICJib2xkIiwgc2l6ZSA9ICgxNSkpLAogICMgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKICAjIHNhdmVfcGF0aCA8LSBwYXN0ZShjKCIuLy4uL2ltZ3MvIiwgaW50ZXJlc3RlZF9jb2xzW2ldLCAiLnBuZyIpLCBjb2xsYXBzZSA9ICIiKQogICMgZ2dzYXZlKHNhdmVfcGF0aCkKICBwcmludChwbHQpCn0KYGBgCgpTaW5jZSB0aGUgYWJvdmUgZG9lc24ndCByZWFsbHkgbWFrZSBzZW5zZSAob25seSA3OCBjb25maXJtZWQgY2FzZXMgd2l0aCBvdmVyIGEgdGhvdXNhbmQgZGVhdGhzKSwgSSBhbSBnb2luZyB0byBhbmFseXplIG9uIGEgcGVyIGNvdW50eSBiYXNpcyBhbmQgbWF5YmUgdGhhdCBkYXRhIHdpbGwgYmUgbW9yZSBjbGVhci4KCmBgYHtyfQp0eF9ieV9kYXlfYmFzZWRfb25fY291bnR5IDwtIHR4X2NvdW50eV9kYXRhICU+JSAKICBzZWxlY3QoZGF0ZSwgY29uZmlybWVkX2Nhc2VzLCBkZWF0aHMpICU+JQogIGdyb3VwX2J5KGRhdGUpICU+JSAKICBzdW1tYXJpc2VfYWxsKHN1bSwgbmEucm0gPSBUKSAlPiUKICBhcnJhbmdlKGRhdGUpCgojIGludGVyZXN0ZWRfY29scyA8LSBjKCJjb25maXJtZWRfY2FzZXMiLCAiZGVhdGhzIikKIyBjb2xfbGFiZWxzIDwtIGMoIlRvdGFsIENhc2VzIiwgIlRvdGFsIERlYXRocyIpCiMgCiMgZm9yIChpIGluIDE6bGVuZ3RoKGNvbF9sYWJlbHMpKXsKIyAgIHByaW50KGkpCiMgICB0aXRsZSA8LSBwYXN0ZShjKCJUZXhhcyAiLCBjb2xfbGFiZWxzW2ldKSwgY29sbGFwc2UgPSAiIikKIyAgIHBsdCA8LSBnZ3Bsb3QodHhfYnlfZGF5X2Jhc2VkX29uX2NvdW50eSwKIyAgICAgICAgYWVzKHg9ZGF0ZSwgeT1nZXQoaW50ZXJlc3RlZF9jb2xzW2ldKSkpKwojICAgIyBnZW9tX3BvaW50KGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpLCBzaXplPS41KSsKIyAgICMgZ2VvbV9saW5lKGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpKSsKIyAgICMgZ2VvbV9wb2ludChzaXplPS41KStnZW9tX2xpbmUoKSsKIyAgICAgZ2VvbV9saW5lKGNvbG9yKSsKIyAgIGxhYnMoeSA9IGNvbF9sYWJlbHNbaV0sIHggPSAiRGF0ZSIsIHRpdGxlID0gdGl0bGUpCiMgICAjIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSwKIyAgICMgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkKIyAgICMgc2F2ZV9wYXRoIDwtIHBhc3RlKGMoIi4vLi4vaW1ncy8iLCBpbnRlcmVzdGVkX2NvbHNbaV0sICIucG5nIiksIGNvbGxhcHNlID0gIiIpCiMgICAjIGdnc2F2ZShzYXZlX3BhdGgpCiMgICBwcmludChwbHQpCiMgfQoKYGBgCmBgYHtyfQp0eF9ieV9kYXlfYmFzZWRfb25fY291bnR5CmBgYAoKCgpgYGB7cn0KbGlicmFyeShzY2FsZXMpCiMgdHhfYnlfZGF5X2Jhc2VkX29uX2NvdW50eSAlPiUgcGl2b3RfbG9uZ2VyKCFkYXRlLCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gImNvdW50IikKZ2dwbG90KHR4X2J5X2RheV9iYXNlZF9vbl9jb3VudHkgJT4lIHBpdm90X2xvbmdlcighZGF0ZSwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJjb3VudCIpLAogICAgICAgYWVzKHg9ZGF0ZSwgeT1jb3VudCwgZ3JvdXA9dHlwZSwgY29sb3IgPSB0eXBlKSkrCiAgICAgICAgIGdlb21fbGluZSgpKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIsCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHRyYW5zX2JyZWFrcygnbG9nMTAnLCBtYXRoX2Zvcm1hdCgxMF4ueCkpKSsKICBzY2FsZV9jb2xvcl9tYW51YWwobGFiZWxzID0gYygiQ29uZmlybWVkIENhc2VzIiwgIkRlYXRocyIpLCB2YWx1ZXMgPSBjKCJjb25maXJtZWRfY2FzZXMiPSJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJkZWF0aHMiPSJyZWQiKSkrCiAgbGFicyh5ID0gIlRvdGFsIFBlcnNvbnMiLCB4ID0gIkRhdGUiLCBjb2xvciA9ICIiKSsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSkpKwogIGdndGl0bGUoIlRleGFzIENPVklELTE5IENhc2VzIikKICBnZ3NhdmUoIi4vLi4vaW1ncy90ZXhhc19jb3ZpZF9jYXNlc190b3RhbC5wbmciKQogICMgc2NhbGVfeV9sb2cxMCgpCiAgICAgICAgICMgbGFicyh5ID0gIlRvdGFsIFBlcnNvbnMiLCB4ID0gIkRhdGUiKSkKCiMgKQojIAojIHBsdCA8LSBnZ3Bsb3QoY29pX2Rvd25zYW1wbGVkLAojICAgICAgICBhZXMoeD1kYXRlLCB5PWdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBncm91cD1jb3VudHJ5X3JlZ2lvbl9jb2RlLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcj1jb3VudHJ5X3JlZ2lvbl9jb2RlKSkrCiMgICBnZW9tX3BvaW50KGFlcyh5PXJvbGxtZWFuKGdldChpbnRlcmVzdGVkX2NvbHNbaV0pLCBrPTEwLCBuYS5wYWQ9VFJVRSkpLCBzaXplPS41KSsKIyAgIGdlb21fbGluZShhZXMoeT1yb2xsbWVhbihnZXQoaW50ZXJlc3RlZF9jb2xzW2ldKSwgaz0xMCwgbmEucGFkPVRSVUUpKSkrCiMgICAjIGdlb21fcG9pbnQoc2l6ZT0uNSkrZ2VvbV9saW5lKCkrCiMgICBsYWJzKHkgPSBjb2xfbGFiZWxzW2ldLCB4ID0gIkRhdGUiLCBjb2xvciA9ICJDb3VudHJ5IikrCiMgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJIZWx2ZXRpY2EiLCBmYWNlID0gImJvbGQiLCBzaXplID0gKDE1KSksCiMgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpKQojICAgc2F2ZV9wYXRoIDwtIHBhc3RlKGMoIi4vLi4vaW1ncy8iLCBpbnRlcmVzdGVkX2NvbHNbaV0sICIucG5nIiksIGNvbGxhcHNlID0gIiIpCiMgICBnZ3NhdmUoc2F2ZV9wYXRoKQojICAgcHJpbnQocGx0KQpgYGAKCmBgYHtyfQp0eF9jb3VudHlfZGF0YQpgYGAKCgpgYGB7cn0KdHhfc3RhdGUgPC0gbWFwX2RhdGEoInN0YXRlIikgJT4lIHN1YnNldChyZWdpb24gPT0gInRleGFzIikKdHhfY291bnR5X21hcF9kYXRhIDwtIG1hcF9kYXRhKCJjb3VudHkiKSAlPiUgc3Vic2V0KHJlZ2lvbiA9PSAidGV4YXMiKQoKdHhfc3RhdGUKdHhfY291bnR5X21hcF9kYXRhCgojIExvd2VyY2FzZQp0eF9jb3VudHlfZGF0YSRjb3VudHlfbmFtZSA8LSB0b2xvd2VyKHR4X2NvdW50eV9kYXRhJGNvdW50eV9uYW1lKQoKIyBSZW1vdmUgJyBjb3VudHknCnR4X2NvdW50eV9kYXRhJGNvdW50eV9uYW1lIDwtIHN1YigiXFxzKmNvdW50eVxcYi4qIiwgIiIsIHR4X2NvdW50eV9kYXRhJGNvdW50eV9uYW1lKQp0eF9jb3VudHlfZGF0YQoKIyBKb2luIHRoZSBkYXRhIHdpdGggc3RhdGUgZ2VvIGluZm8KdHhfZ2VvX2RhdGEgPC0gbGVmdF9qb2luKHR4X2NvdW50eV9tYXBfZGF0YSwgdHhfY291bnR5X2RhdGEsIGJ5ID0gYygic3VicmVnaW9uIiA9ICJjb3VudHlfbmFtZSIpKQp0eF9nZW9fZGF0YQpgYGAKYGBge3J9CnR4X2dlb19kYXRhJGNvdW50eV9maXBzX2NvZGUgPC0gYXMuaW50ZWdlcih0eF9nZW9fZGF0YSRjb3VudHlfZmlwc19jb2RlKQp0eF9kYXRhX3Bsb3QgPC0gdHhfZ2VvX2RhdGEgJT4lIGdyb3VwX2J5KCkKcGxvdF92c19jb3VudHkodHhfZ2VvX2RhdGEsICJjb25maXJtZWRfY2FzZXMiKQojIGdncGxvdCh0eF9nZW9fZGF0YSkgKwojICAgICAgICAgIGNvb3JkX21hcCgpICsgCiMgICBnZ3RoZW1lczo6dGhlbWVfbWFwKCkrCiMgICBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBzdWJyZWdpb24sIGZpbGwgPSBjb25maXJtZWRfY2FzZXMpKQojIHBjX2NvbnRfaW93YSA8LSBnZW9tX3BvbHlnb24oYWVzKGxvbmcsIGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IHBjaGFuZ2UpLAojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsIHNpemUgPSAwLjIpCmBgYAoKYGBge3J9CiMgZGFsbGFzX2RhdGEgPC0gdHhfY291bnR5X2RhdGEgJT4lIGZpbHRlcihjb3VudHlfbmFtZSA9PSAiZGFsbGFzIikgCmRhbGxhc19kYXRhIDwtIHR4X2NvdW50eV9kYXRhICU+JSBmaWx0ZXIoY291bnR5X25hbWUgPT0gImRhbGxhcyIpICU+JSAKICBzZWxlY3QoZGF0ZSwgY29uZmlybWVkX2Nhc2VzLCBkZWF0aHMpCgpnZ3Bsb3QoZGFsbGFzX2RhdGEgJT4lIHBpdm90X2xvbmdlcighZGF0ZSwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJjb3VudCIpLAogICAgICAgYWVzKHg9ZGF0ZSwgeT1jb3VudCwgZ3JvdXA9dHlwZSwgY29sb3IgPSB0eXBlKSkrCiAgICAgICAgIGdlb21fbGluZSgpKwogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IHRyYW5zX2JyZWFrcygibG9nMTAiLCBtYXRoX2Zvcm1hdCgxMF4ueCkpKSsKICBzY2FsZV95X2xvZzEwKGJyZWFrcz1jKDEwMCwgMzAwLCA1MDAsIDEwMDAsIDMwMDAsIDUwMDAsIDEwMDAwLCAzMDAwMCwgNTAwMDAsIDEwMDAwMCwgMzAwMDAwKSwKICAgICAgICAgICAgICAgIGxhYmVscz1jKCcxMDAnLCAnMzAwJywgJzUwMCcsICcxMDAwJywgJzMwMDAnLCAnNTAwMCcsICcxMDAwMCcsICczMDAwMCcsICc1MDAwMCcsICcxMDAwMDAnLCAnMzAwMDAwJykpKwogIHNjYWxlX2NvbG9yX21hbnVhbChsYWJlbHMgPSBjKCJDb25maXJtZWQgQ2FzZXMiLCAiRGVhdGhzIiksIHZhbHVlcyA9IGMoImNvbmZpcm1lZF9jYXNlcyI9ImJsdWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRlYXRocyI9InJlZCIpKSsKICBsYWJzKHkgPSAiVG90YWwgUGVyc29ucyIsIHggPSAiRGF0ZSIsIGNvbG9yID0gIiIpKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIkhlbHZldGljYSIsIGZhY2UgPSAiYm9sZCIsIHNpemUgPSAoMTUpKSkrCiAgZ2d0aXRsZSgiRGFsbGFzIENPVklELTE5IENhc2VzIikKICBnZ3NhdmUoIi4vLi4vaW1ncy9kYWxsYXNfY292aWRfY2FzZXNfdG90YWwucG5nIikKYGBgCgoKYGBge3J9CnN1YnNldF9jZW5zdXMKYGBgCgoKCgoKCgoKCgoKCgoKCg==